package com.wsd.smartcarwasher.service;

import com.thoughtworks.xstream.XStream;
import com.wsd.smartcarwasher.constans.Constant;
import com.wsd.smartcarwasher.domain.*;
import com.wsd.smartcarwasher.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.KeyStore;
import java.util.*;

import static com.wsd.smartcarwasher.constans.Constant.*;
import static com.wsd.smartcarwasher.service.WxPayService.changeY2F;

@Component
public class TimeTaskService{
    private static final Logger logger = LoggerFactory.getLogger(TimeTaskService.class);

    @Resource
    private ProrateService prorateService;

    static int count = 0;

    @Scheduled(cron = "0 30 21 * * ?")
    public void run() {
        logger.info("时间=" + new Date() + " 执行了" + count + "次"); // 1次
        List<OrderInfo>  orderList = prorateService.queryAllOrdersByCashWithdrawal();
        logger.info("查询到昨天需要分账订单数："+orderList.size());

        SortedMap<Integer, List<OrderInfo>> orderMapByM = new TreeMap<>();
        //按照 机器id 排单
        orderList.forEach(orderInfo -> {
            List<OrderInfo>  mlist= null;
            if(orderMapByM.containsKey(orderInfo.getMachineId())){
                mlist=orderMapByM.get(orderInfo.getMachineId());
            }else{
                mlist = new ArrayList<>();
                orderMapByM.put(orderInfo.getMachineId(),mlist);
            }
            mlist.add(orderInfo);
        });


        //
        orderMapByM.forEach((k,v)->{
            try {
                Machine machine =  prorateService.queryMachineById(k);

                SortedMap<Integer, List<OrderInfo>> orderMapByp = new TreeMap<>();

                List<OrderInfo>  plist= null;
                //按照运营商排单
                for (OrderInfo order:  v) {
                    if(orderMapByp.containsKey(order.getPartnerId())){
                        plist=orderMapByp.get(order.getPartnerId());
                    }else{
                        plist = new ArrayList<>();
                        orderMapByp.put(order.getPartnerId(),plist);
                    }
                    plist.add(order);
                }
                //排单完成 开始转账
                orderMapByp.forEach((p,l)->{
                    Integer price =0;
                    String partner_trade_no = OrderCodeFactory.getOrderCode(machine.getId().longValue());
                    for(OrderInfo order: l){
                        price +=order.getPayPrice().movePointRight(2).multiply(machine.getProfitRatio()).intValue();
                        order.setProrateSn(partner_trade_no);
                    }
                    //String partner_trade_no = OrderCodeFactory.getOrderCode(machine.getId().longValue());
                    Map<String, String> res=cashWithdrawal(price,p,partner_trade_no,k);
                    processRes(res,l,partner_trade_no,p,price,k);
                });
                Thread.sleep(30);
            }catch (Exception e){
                e.printStackTrace();
                logger.info("分账线程休眠30 秒发生异常");
            }
        });

    }


    /**
     *
     * @param price
     * @return
     */
    public Map<String, String> cashWithdrawal(int price,int partnerId,String partner_trade_no,int mid){
        Partner partner =  prorateService.getPartnerById(partnerId);
        //有效的运营商
        try {
            if(partner!=null&&StringUtils.isNotBlank(partner.getOpenId())){
                String desc = "蜗牛智能洗车服务"+mid+"设备分账"+price/100+"元";
                // 参数：开始生成第一次签名
                String  nonce_str=RandomUtils.generateMixString(32);
                SortedMap<String, Object> parameters = new TreeMap<>();
                parameters.put("mch_appid", OFFICIAL_APP_ID);
                parameters.put("mchid", MCH_ID);
                parameters.put("partner_trade_no", partner_trade_no);
                parameters.put("nonce_str", nonce_str);
                parameters.put("openid", partner.getOpenId());
                parameters.put("check_name", "NO_CHECK");
                parameters.put("amount", price);
                parameters.put("spbill_create_ip", IP_ADDR);
                parameters.put("desc", desc);
                String sign =  getSign(parameters);

                Transfers transfers = new Transfers();
                transfers.setAmount(price);
                transfers.setCheck_name("NO_CHECK");
                transfers.setDesc(desc);
                transfers.setMch_appid(OFFICIAL_APP_ID);
                transfers.setMchid(MCH_ID);
                transfers.setNonce_str(nonce_str);
                transfers.setOpenid(partner.getOpenId());
                transfers.setPartner_trade_no(partner_trade_no);
                transfers.setSign(sign);
                transfers.setSpbill_create_ip(IP_ADDR);
                String xml = transferXml1(transfers);
                logger.info(xml);
                CloseableHttpResponse response =  HttpUtil.Post(WITHDRAW_URL, xml, true);
                String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
                Map<String, String> transferMap = CommonUtil.parseXml(transfersXml);
                return transferMap;
            }else {
                logger.info("运营商不存在，分账失败");
            }
        } catch (Exception e) {
            logger.info("***************分账异常***************");
            e.printStackTrace();
        }
        return null;
    }

    /**
     *
     * @param price
     * @return
     */
    public Map<String, String> cashRefundByUser(int price,String partner_trade_no,UserInfo user){
        //有效的运营商
        try {
            if(user!=null&&StringUtils.isNotBlank(user.getOpenid())){
                BigDecimal pricee=BigDecimal.valueOf(price/100);
                String desc = "蜗牛智能洗车服务退款"+pricee+"元";
                // 参数：开始生成第一次签名
                String  nonce_str=RandomUtils.generateMixString(32);
                SortedMap<String, Object> parameters = new TreeMap<>();
                parameters.put("appid", APP_ID);
                parameters.put("mch_id", MCH_ID);
                parameters.put("nonce_str", nonce_str);
                parameters.put("out_trade_no", partner_trade_no);
                parameters.put("out_refund_no", partner_trade_no);
                parameters.put("total_fee", changeY2F(price));
                parameters.put("refund_fee",changeY2F(price));
                String sign =  getSign(parameters);

                Transfers transfers = new Transfers();
                transfers.setMch_appid(APP_ID);
                transfers.setMchid(MCH_ID);
                transfers.setNonce_str(nonce_str);
                transfers.setOut_refund_no(partner_trade_no);
                transfers.setOut_trade_no(partner_trade_no);
                transfers.setTotal_fee(changeY2F(price));
                transfers.setSign_type("MD5");
                transfers.setRefund_fee(changeY2F(price));
                transfers.setSign(sign);
                String xml = transferXmlRefund(transfers);
                logger.info(xml);
                CloseableHttpResponse response =  HttpUtil.Post(REFUND_URL, xml, true);
                String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
                Map<String, String> transferMap = CommonUtil.parseXml(transfersXml);
                return transferMap;
            }else {
                logger.info("用户不存在，退款失败失败");
            }
        } catch (Exception e) {
            logger.info("***************用户不存在，退款失败失败***************");
            e.printStackTrace();
        }
        return null;
    }


    /**
     *
     * @param price
     * @return
     */
    public Map<String, String> cashWithdrawalByUser(int price,String partner_trade_no,UserInfo user){
        //有效的运营商
        try {
            if(user!=null&&StringUtils.isNotBlank(user.getOpenid())){
                BigDecimal pricee=BigDecimal.valueOf(price/100);
                String desc = "蜗牛智能洗车服务退款"+pricee+"元";
                // 参数：开始生成第一次签名
                String  nonce_str=RandomUtils.generateMixString(32);
                SortedMap<String, Object> parameters = new TreeMap<>();
                parameters.put("mch_appid", APP_ID);
                parameters.put("mchid", MCH_ID);
                parameters.put("partner_trade_no", partner_trade_no);
                parameters.put("nonce_str", nonce_str);
                parameters.put("openid", user.getOpenid());
                parameters.put("check_name", "NO_CHECK");
                parameters.put("amount", price);
                parameters.put("spbill_create_ip", IP_ADDR);
                parameters.put("desc", desc);
                String sign =  getSign(parameters);

                Transfers transfers = new Transfers();
                transfers.setAmount(price);
                transfers.setCheck_name("NO_CHECK");
                transfers.setDesc(desc);
                transfers.setMch_appid(APP_ID);
                transfers.setMchid(MCH_ID);
                transfers.setNonce_str(nonce_str);
                transfers.setOpenid(user.getOpenid());
                transfers.setPartner_trade_no(partner_trade_no);
                transfers.setSign(sign);
                transfers.setSpbill_create_ip(IP_ADDR);
                String xml = transferXml1(transfers);
                logger.info(xml);
                CloseableHttpResponse response =  HttpUtil.Post(WITHDRAW_URL, xml, true);
                String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
                Map<String, String> transferMap = CommonUtil.parseXml(transfersXml);
                return transferMap;
            }else {
                logger.info("用户不存在，退款失败失败");
            }
        } catch (Exception e) {
            logger.info("***************用户不存在，退款失败失败***************");
            e.printStackTrace();
        }
        return null;
    }



    /**
     *
     * @param res
     */
    @Transactional
    public int processRes(Map<String, String> res,List<OrderInfo> orderInfoList,
                           String prorateSn,Integer partnerId,Integer amount,Integer machinedId
    ){

        int update=0;
        Prorate  prorate = new Prorate();
        prorate.setMachineId(machinedId);
        prorate.setProrateSn(prorateSn);
        prorate.setPartnerId(partnerId);
        prorate.setProrateTime(new Date());
        BigDecimal feeNo = new BigDecimal(amount);
        feeNo = feeNo.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);//分转元
        prorate.setStatus(100);
        prorate.setAmount(feeNo);
        try {

            int rows = 0;
            if (res!=null &&res.size()>0
                    && res.get("result_code").equals("SUCCESS")
                    && res.get("return_code").equals("SUCCESS")) {

                prorate.setPayStatus(0);
                prorate.setDesc("成功");
                prorateService.cashWithdrawalSuccess(orderInfoList);
                logger.info(partnerId+":分账成功"+feeNo);
                rows = 1;
            }else if(res ==null || res.get("result_code").equals("FAIL")) {

                String msg = res ==null ? "运营商不存在" : res.get("err_code_des");
                prorate.setPayStatus(1);
                prorate.setDesc(msg);
                logger.info(partnerId+":分账失败"+feeNo);
                prorateService.cashWithdrawalFail(orderInfoList);
            }

            int rows1 =  prorateService.insertSelective(prorate);
            if(rows1 <1){
                logger.info("插入分账记录失败");
            }
            logger.info("分账程序执行成功");
            return rows;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("修改订单分账失败了!");
        }

        return 0;

    }


    private String getSign(SortedMap<String, Object> packageParams) throws Exception {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();

        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=woniuzhinengkejiyouxiangongsi000");
        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }




    /**
     * 构造企业付款xml参数
     * @param
     * @return
     */
    public  String transferXml(Transfers transfers){
        XStream xStream = new XStream();
        xStream.autodetectAnnotations(true);
        xStream.alias("xml", Transfers.class);
        return xStream.toXML(transfers);
    }


    public  String transferXml1(Transfers pi) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        sb.append("<").append("mch_appid").append(">").append(pi.getMch_appid()).append("</").append("mch_appid").append(">");
        sb.append("<").append("mchid").append(">").append(pi.getMchid()).append("</").append("mchid").append(">");
        sb.append("<").append("nonce_str").append(">").append(pi.getNonce_str()).append("</").append("nonce_str").append(">");
        sb.append("<").append("partner_trade_no").append(">").append(pi.getPartner_trade_no()).append("</").append("partner_trade_no").append(">");
        sb.append("<").append("openid").append(">").append(pi.getOpenid()).append("</").append("openid").append(">");
        sb.append("<").append("check_name").append(">").append(pi.getCheck_name()).append("</").append("check_name").append(">");
        sb.append("<").append("amount").append(">").append(pi.getAmount()).append("</").append("amount").append(">");
        sb.append("<").append("desc").append(">").append(pi.getDesc()).append("</").append("desc").append(">");
        sb.append("<").append("spbill_create_ip").append(">").append(pi.getSpbill_create_ip()).append("</").append("spbill_create_ip").append(">");
        sb.append("<").append("sign").append(">").append(pi.getSign()).append("</").append("sign").append(">");
        sb.append("</xml>");
        return sb.toString().trim();
    }

    public  String transferXmlRefund(Transfers pi) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        sb.append("<").append("appid").append(">").append(pi.getMch_appid()).append("</").append("appid").append(">");
        sb.append("<").append("mch_id").append(">").append(pi.getMchid()).append("</").append("mch_id").append(">");
        sb.append("<").append("nonce_str").append(">").append(pi.getNonce_str()).append("</").append("nonce_str").append(">");
        sb.append("<").append("sign").append(">").append(pi.getSign()).append("</").append("sign").append(">");
        sb.append("<").append("sign_type").append(">").append(pi.getSign_type()).append("</").append("sign_type").append(">");
        sb.append("<").append("out_trade_no").append(">").append(pi.getOut_trade_no()).append("</").append("out_trade_no").append(">");
        sb.append("<").append("out_refund_no").append(">").append(pi.getOut_refund_no()).append("</").append("out_refund_no").append(">");
        sb.append("<").append("total_fee").append(">").append(pi.getTotal_fee()).append("</").append("total_fee").append(">");
        sb.append("<").append("refund_fee").append(">").append(pi.getRefund_fee()).append("</").append("refund_fee").append(">");
//        sb.append("<").append("sign").append(">").append(pi.getSign()).append("</").append("sign").append(">");
        sb.append("</xml>");
        return sb.toString().trim();
    }
}
